//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// Status bar control.
//

# include "StdAfx.h"
# include "Resource.h"
# include "Status.h"
# include "Toolbar.h"
# include "Levels.h"
# include "Scale.h"
# include "Log.h"
# include "WebMap.h"
# include "MapView.h"
# include "PtAlgo.h"
# include "Wrappers.h"
# include "PrintUnits.h"
# include "Globals.h"

static DWORD g_dwStatusThreadID;

enum {
	sbStatus      = 0,
	sbProgress    = 1,
	sbProgressNum = 2,
	sbBlank1      = 3,
	sbScale       = 4,
	sbLevel       = 5,
	sbGoogle      = 6,
	sbBlank2      = 7,
	sbPosition    = 8,
};

void _HideProgressStatus ();

static
void _SendMessage (HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam) {
	if (::GetCurrentThreadId () == g_dwStatusThreadID) {
		// NOTE: the timeout is used to avoid deadlocks.
		DWORD dwRet = 0;
		::SendMessageTimeout (_hWnd, _uMsg, _wParam, _lParam, SMTO_ABORTIFHUNG, 1000, & dwRet);
	} else
		::PostMessage (_hWnd, _uMsg, _wParam, _lParam);
}

/////////////////////////////////////////////

HWND g_hStatusWnd;

bool InitStatusWindow () {
	assert (g_hWnd);

	g_hStatusWnd = ::CreateStatusWindow (WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBT_TOOLTIPS | SBARS_SIZEGRIP, GetStr (IDS_NO_FILES), g_hWnd, 101);
	if (! g_hStatusWnd)
		return false;

	int widths [] = {
		100, // Status
		108, // Progress bar
		40,  // Progress %
		20,
		70,  // Scale
		55,  // Level
		30,  // Google level
		20,
		155, // Position
	};

	// Get width factor for non-standard font in the status bar.	
	const HFONT hStatusFont = reinterpret_cast<HFONT> (::SendMessage (g_hStatusWnd, WM_GETFONT, (WPARAM) g_hFont, FALSE));
	CClientDC dcStatus (g_hStatusWnd);
	const HFONT hPrevFont = reinterpret_cast<HFONT> (::SelectObject (dcStatus, hStatusFont));
	TEXTMETRIC tm;
	::GetTextMetrics (dcStatus, & tm);
	const float fScale = tm.tmAveCharWidth/5.f;
	::SelectObject (dcStatus, hPrevFont);
/*
	RECT rect;
	::GetWindowRect (g_hStatusWnd, & rect);
	const float fScale = (rect.bottom - rect.top - 4)/(20. - 4);
*/
	for (size_t c = 0; c < sizeof (widths)/sizeof (widths [0]); ++ c) {
		if (c != sbProgress)
			widths [c] *= fScale;
		if (c >= 1)
			widths [c] += widths [c - 1];
	}
	::SendMessage (g_hStatusWnd, SB_SETPARTS, sizeof (widths)/sizeof (widths [0]), long (widths));
	::SendMessage (g_hStatusWnd, SB_SETTEXT, sbBlank1 | SBT_NOBORDERS, long (NULL));
	::SendMessage (g_hStatusWnd, SB_SETTEXT, sbBlank2 | SBT_NOBORDERS, long (NULL));

	g_dwStatusThreadID = ::GetCurrentThreadId ();

	return true;
}

void DestroyStatusWindow () {
	// TODO:
}

void ResetStatus () {
	SetStatus (GetStr (IDS_NO_FILES));
	SetProgressStatus (0);
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbProgressNum, (LPARAM) "");
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbScale,       (LPARAM) "");
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbLevel,       (LPARAM) "");
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbPosition,    (LPARAM) "");
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbGoogle,      (LPARAM) "");

	if (g_hScaleCB) {
		DWORD dwRet = 0;
		::SendMessageTimeout (g_hScaleCB, WM_SETTEXT, sbStatus, (LPARAM) "", SMTO_ABORTIFHUNG, 1000, & dwRet);
	}
}

/////////////////////////////////////////////

void SetStatusReady () {
	_HideProgressStatus ();

	if (GetWarningsCount () > 0)
		SetStatus (GetStr (IDS_READY_WARN));
	else
		SetStatus (GetStr (IDS_READY));
}

char g_strStatus [64];

void SetStatus (const char * _strStatus) {
	if (::strcmp (_strStatus, g_strStatus) == 0)
		return;

	g_strStatus [63] = '\0';
	::strncpy (g_strStatus, _strStatus, 64);

	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbStatus, (LPARAM) g_strStatus);
}

/////////////////////////////////////////////

static int g_iProgress = 0;

static
void _HideProgressStatus () {
	g_iProgress = 0;
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbProgress | SBT_OWNERDRAW, g_iProgress);
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbProgressNum, (LPARAM) "");
}

void SetProgressStatus (int _iProgress) {
	if (_iProgress > 100)
		_iProgress = 100;
	if (_iProgress < 0)
		_iProgress = 0;

	if (_iProgress == g_iProgress)
		return;
	g_iProgress = _iProgress;

	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbProgress | SBT_OWNERDRAW, g_iProgress);

	static char strText [32];
	strText [31] = '\0';
	::sprintf (strText, "% 3d%%", g_iProgress);
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbProgressNum, (LPARAM) strText);
}

/////////////////////////////////////////////

void SetPositionStatus (const point_t & _pt) {
/*
	if (_pt.x < -180)
		_pt.x = -180;
	if (_pt.x > 180)
		_pt.x = 180;

	if (_pt.y < -90)
		_pt.y = -90;
	if (_pt.y > 90)
		_pt.y = 90;
*/
	static char strText [64];
	strText [63] = '\0';
	PrintPosition (strText, _pt);
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbPosition, (LPARAM) strText);
}

/////////////////////////////////////////////

void SetScaleStatus (float _fScale) {
	static char strText [64];
	strText [63] = '\0';
	::sprintf (strText, "1 : %d", long (_fScale*c_pixels_per_cm*100));
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbScale, (LPARAM) strText);

	static char strText2 [64];
	strText2 [63] = '\0';
	GetZoomLevel (_fScale, strText2);
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbLevel, (LPARAM) strText2);

	static char strText3 [32];
	strText3 [31] = '\0';
	GetScale (_fScale, strText3);
	if (g_hScaleCB) {
		DWORD dwRet = 0;
		::SendMessageTimeout (g_hScaleCB, WM_SETTEXT, sbStatus, (LPARAM) strText3, SMTO_ABORTIFHUNG, 1000, & dwRet);
	}

	static char strGoogle [8];
	strGoogle [0] = '\0';
	if (g_bShowGoogleMaps)
		::_snprintf (strGoogle, 8, "G:%d", GetGoogleMapsLevel (_fScale));
	_SendMessage (g_hStatusWnd, SB_SETTEXT, sbGoogle, (LPARAM) strGoogle);
}


//////////////////////////////////////////////////////////////////////////
CProgressBar::CProgressBar (size_t _cFrom, size_t _cTo) :
	m_cProgressFrom (_cFrom),
	m_cProgressTo (_cTo),
	m_cValueFrom (_cFrom),
	m_cValueTo (_cTo),
	m_cLastProgress (0)
{}

size_t CProgressBar::Progress (size_t _cValue) const {
	if (m_cProgressFrom >= m_cProgressTo)
		return m_cProgressTo;
	if (m_cValueFrom >= m_cValueTo)
		return m_cProgressFrom;
	
	if (_cValue < m_cValueFrom)
		_cValue = m_cValueFrom;
	if (_cValue > m_cValueTo)
		_cValue = m_cValueTo;

	return m_cProgressFrom + (m_cProgressTo - m_cProgressFrom)*(_cValue - m_cValueFrom)/(m_cValueTo - m_cValueFrom);
}

void CProgressBar::SetValue (size_t _cValue) const {
	const size_t cCurrent = Progress (_cValue);
	if (cCurrent <= m_cLastProgress)
		return;

	SetProgressStatus (cCurrent);
	m_cLastProgress = cCurrent;
}
	
void CProgressBar::SetValueRange (size_t _cFromValue, size_t _cToValue) {
	m_cValueFrom       = _cFromValue;
	m_cValueTo         = _cToValue;
	m_cLastSubBarValue = _cFromValue;
}

CProgressBar CProgressBar::GetSubBar (size_t _cFromValue, size_t _cToValue) const {
	return CProgressBar (Progress (_cFromValue), Progress (_cToValue));
}

CProgressBar CProgressBar::GetNextSubBar (size_t _cLengthValue) const {
	const size_t cFirst = m_cLastSubBarValue;
	const size_t cLast  = m_cLastSubBarValue + _cLengthValue;
	
	m_cLastSubBarValue = cLast;
	return GetSubBar (cFirst, cLast);
}
